import random
import copy
import logging
import numpy as np

from util.util_log import setup_logging
from util.util_csv import save_csv, save_to_csv
from util.util_image import save_img, save_img_xyz, save_line_chart, save_images_3x2, draw_img
from util.util_ris_pattern import point_2_phase, phase_2_pattern, phase_2_pattern_xyz, eps, \
    phase_2_bit, phaseBit_2_deg, phase_2_pattern_xyz_fft
from util.util_analysis_plane import get_peaks, get_peak_nth

from multi_beam_trace.util_create_trace import create_scan_traces_theta, \
    create_scan_traces_phi, create_scan_traces_theta_phi
from multi_beam_trace.util_phase_pattern import traces_2_phaseBits, traces_2_phaseRads, phaseBits_2_patterns
from multi_beam_trace.util_analysis import get_phase_neighbor_diff, get_antenna_indicators_normalized, \
    get_antenna_indicators_normalized_item, compare_arrays

from multi_beam.multi_beam_PS_complex import psm_complex_beam_n
from multi_beam.multi_beam_QE import qe_beam_N


# 配置日志，默认打印到控制台，也可以设置打印到文件
# setup_logging()
setup_logging(log_file="../files/multi-beam-trace/beam2/QE/L=L1+L4/trace_2025-03-20-1317-16beam-ps-complex.txt")
# 获取日志记录器并记录日志
logger = logging.getLogger("[multi-beam-trace-GA]")


# ============================================= 天线相关计算 =======================================
# pattern 计算 peaks
def pattern_2_peaks(pattern):
    # pattern 转dB
    pattern_dbw = 20 * np.log10(np.abs(pattern) / np.max(np.max(np.abs(pattern))) + eps)
    # pattern找峰值
    peaks = get_peaks(pattern_dbw)
    return peaks


# 计算phase的方向图
def phaseBit_2_pattern(phaseBit, bit_num):
    phaseBitDeg = phaseBit_2_deg(phaseBit, bit_num)
    phaseBitRad = np.deg2rad(phaseBitDeg)
    # pattern_xyz, x, y, z = phase_2_pattern_xyz(phaseBitRad)
    pattern_xyz, x, y = phase_2_pattern_xyz_fft(phaseBitRad)  # FFT法计算, 快速
    # return np.abs(pattern_xyz), x, y
    return pattern_xyz, x, y


# 码阵转bit
def phases_rad_2_bit(phaseRads, bit_num):
    phaseBits = []
    for phaseRad in phaseRads:
        phaseBit, phaseDeg = phase_2_bit(phaseRad, bit_num)
        phaseBits.append(phaseBit)
    return phaseBits


# ============================================= 遗传算法 ===========================================
class GeneticAlgorithmBeamTrace():
    __bit_num = 0       # 比特数
    __beam_num = 0      # 波束数

    def __init__(self, bit_num, beam_num, population_size=50, num_generations=100, num_parents=10, mutation_rate=0.1):
        # 初始化阵列相关: 参数设置
        self.__bit_num = bit_num
        self.__beam_num = beam_num
        # 初始化遗传算法相关: 参数设置
        self.population_size = population_size
        self.num_generations = num_generations
        self.num_parents = num_parents
        self.mutation_rate = mutation_rate
        # 初始化遗传算法相关: fitness
        self.phaseBitTarget = 1
        self.phaseBitHistoryList = []       # 历史时刻的码阵, 从远到近
        self.fitness_l4_map = {}            # fitness - l4 约束的值与数量对应, eg: 1bit = {1: 512, 0: 512}
        self.main_lope_pos_list = []        #
        # 初始化遗传算法相关: 返回
        self.population = None
        self.best_individual = None
        self.best_fitness = None
        self.best_fitness_history = []  # 保存每一代的最佳适应度值
        self.best_individual_history = []  # 保存每一代的最佳适应度值的个体


    # 适应度: L0 -- 主瓣检查: 检查是否是最大主瓣位置
    def __fitnes_l0_pos(self, selected_peaks):
        count = 0
        for peak in selected_peaks:
            peak_x = peak[1][0]
            peak_y = peak[1][1]
            for pos in self.main_lope_pos_list:
                pos_x = pos[0]
                pos_y = pos[1]
                if abs(peak_x - pos_x) <= 1 and abs(peak_y - pos_y) <= 1:
                    count += 1
                    break
        return count

    # 适应度: L0 -- 主瓣检查: 检查main_lope_pos位置是否小于3dB
    def __fitnes_l0_3dB(self, pattern):
        count = 0
        pattern_3dB = np.max(pattern) / 2.0
        for pos in self.main_lope_pos_list:
            pos_x = pos[0]
            pos_y = pos[1]
            # logger.info("pattern_3dB=%f, pattern[%d][%d]=%f" % (pattern_3dB, pos_x, pos_y, pattern[pos_x][pos_y]))
            if pattern[pos_x][pos_y] > pattern_3dB:
                count += 1
        return count

    # 适应度: L0 -- 主瓣位置检测
    def fitness_l0(self, peaks, pattern):
        # 获取前 beam_num 个 peaks
        selected_peaks = peaks[:self.__beam_num]
        #
        # count = self.__fitnes_l0_pos(selected_peaks)    # 统计这些峰值在主瓣位置列表中的数量
        count = self.__fitnes_l0_3dB(pattern)           # 统计主瓣位置是否小于3dB
        return np.abs(self.__beam_num - count)

    # 适应度: L1 -- PSLL 部分
    def fitness_l1(self, peaks):
        psll = 0
        # 找第beam_num+1峰(小于3dB)作为 PSLL
        if len(peaks) > self.__beam_num:
            peak_nth = get_peak_nth(peaks, self.__beam_num)
            if peak_nth is not None:
                psll = peak_nth[0]
        return psll

    # 适应度: L2 -- 相邻时刻码阵不同位置数量
    def fitness_l2(self, phaseBit):
        if self.phaseBitHistoryList is None or len(self.phaseBitHistoryList) == 0:
            return 0, 0
        phaseBitBefore = self.phaseBitHistoryList[-1]
        count = np.sum(phaseBit != phaseBitBefore)
        rows, cols = phaseBit.shape
        percentage = round((count / (rows * cols)) * 100, 4)
        return count, percentage

    # 适应度: L3 -- 历史码阵每个阵元工作时长均匀程度
    def fitness_l3(self, phaseBit):
        if self.phaseBitHistoryList is None or len(self.phaseBitHistoryList) == 0:
            return 0, 0, 0, 0, 0
        # 深拷贝 self.phaseBitHistoryList 到 phaseBit_all_list
        phaseBit_all_list = copy.deepcopy(self.phaseBitHistoryList)
        # 将 phaseBit 添加为最后一项
        phaseBit_all_list.append(phaseBit)
        # 统计 phaseBit_history_list 中每个位置的值等于 target 的次数
        count_target = sum(np.array(history == self.phaseBitTarget, dtype=int) for history in phaseBit_all_list)
        # 计算所有元素的平均值
        mean_value = np.mean(count_target)
        # 计算每个元素偏离平均值的平方差，并求和
        deviation_sum = np.sum((count_target - mean_value) ** 2)
        # 计算标准差（偏差平方和开方）
        standard_deviation = np.sqrt(deviation_sum)
        # 计算归一化的标准差 (基于最大值)
        normalized_std_max = standard_deviation / np.max(count_target)
        return count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max

    # 适应度: L4 -- 一段时间内码阵功率为固定值: 可以是码阵为不同值的阵元数量在一段时间内相同
    def fitness_l4(self, phaseBit):
        # 将二维数组展平成一维数组
        flattened = phaseBit.flatten().astype(int)
        # 统计各个值的出现次数
        counts = np.bincount(flattened, minlength=len(self.fitness_l4_map))
        # 计算偏离对应值的方差
        variance = np.sum((counts - list(self.fitness_l4_map.values())) ** 2)
        return counts, int(variance)

    # 适应度: L5 -- 最少工作阵元, 稀疏布阵的推广
    def fitness_l5(self, phaseBit, target):
        # phaseBit是类型为np.array()的二维数组, 每个元素都是float。计算 phaseBit中值为 target 的元素数量
        # 计算 phaseBit 中等于 target 的元素数量
        # phaseBit 是一个 2D numpy 数组
        # target 是 float 类型
        # 使用 numpy 的高效计算方式
        equal_elements = np.count_nonzero(phaseBit == target)
        return equal_elements

    # 适应度: L = L1 + L2 + L3
    def fitness(self, phaseBit):
        # 前置计算, 计算pattern和peaks
        pattern, x, y = phaseBit_2_pattern(phaseBit, self.__bit_num)
        peaks = pattern_2_peaks(pattern)
        #
        # 计算 L0
        l0_main_lope_pos_miss = self.fitness_l0(peaks, pattern)
        # 计算 L1
        l1_psll = self.fitness_l1(peaks)
        # 计算 L2
        l2_count, l2_percentage = self.fitness_l2(phaseBit)
        # # 计算 L3
        # l3_count_target, l3_mean_value, l3_deviation_sum, l3_standard_deviation, l3_normalized_std_max \
        #     = self.fitness_l3(phaseBit)
        # 计算 L4
        # l4_counts, l4_variance = self.fitness_l4(phaseBit)
        # 计算 L5
        l5_counts = self.fitness_l5(phaseBit, 1)
        # 计算 L = L1 + L2 + L3
        # fitness = l1_psll + l2_percentage + l3_normalized_std_max
        # fitness = l1_psll + l2_percentage + l4_variance
        fitness = l0_main_lope_pos_miss * 10000 + l1_psll + l2_percentage + l5_counts
        # fitness = l1_psll + l2_percentage + l5_counts
        # fitness = l1_psll
        # logger.info("l=%f, l1=%f" % (fitness, l1_psll))
        # logger.info("l=%f, l1=%f, l2_percentage=%f, l2_count=%f, l5_counts=%d"
        #             % (fitness, l1_psll, l2_percentage, l2_count, l5_counts))
        logger.info("l=%f, l0=%f, l1=%f, l2_percentage=%f, l2_count=%f, l5_counts=%d"
                    % (fitness, l0_main_lope_pos_miss, l1_psll, l2_percentage, l2_count, l5_counts))
        # logger.info("l=%f, l1=%f, l2=%f, l3=%f" % (fitness, l1_psll, l2_percentage, l3_normalized_std_max))
        return fitness

    def initialize_population(self, phase_mix_init):
        """初始化种群"""
        self.population = [phase_mix_init] * self.population_size

    def init_main_lope_pos(self, phaseBit_target):
        # 计算目标方向图的主瓣坐标, 保存到 self.main_lope_pos_list
        pattern, x, y = phaseBit_2_pattern(phaseBit_target, self.__bit_num)
        peaks = pattern_2_peaks(pattern)
        self.main_lope_pos_list = []
        for i in range(0, self.__beam_num):
            self.main_lope_pos_list.append(peaks[i][1])
        return self.main_lope_pos_list

    def selection(self):
        """选择操作"""
        fitness_scores = [self.fitness(individual) for individual in self.population]
        sorted_indices = np.argsort(fitness_scores)  # 从低到高排序
        selected_parents = [self.population[i] for i in sorted_indices[:self.num_parents]]
        # 获取选中的父代个体对应的适应度值
        selected_fitness_scores = [fitness_scores[i] for i in sorted_indices[:self.num_parents]]
        return selected_parents, selected_fitness_scores

    def crossover(self, parents, offspring_size):
        """交叉操作"""
        offspring = []
        for _ in range(offspring_size):
            parent1, parent2 = random.sample(parents, 2)
            parent1 = np.array(parent1)
            parent2 = np.array(parent2)
            # 获取数组的形状
            shape = parent1.shape
            # 将 parent1 和 parent2 扁平化为一维数组
            flat_parent1 = parent1.flatten()
            flat_parent2 = parent2.flatten()
            # 随机选择一个切割位置
            cut_point = random.randint(0, len(flat_parent1))
            # 生成子代
            child = np.concatenate((flat_parent1[:cut_point], flat_parent2[cut_point:]))
            # 将子代重新塑形为原始的二维数组形状
            child = child.reshape(shape)
            child = child.tolist()
            #
            offspring.append(np.array(child))
        return offspring

    def mutation(self, offspring):
        """变异操作"""
        for individual in offspring:
            if random.random() < self.mutation_rate:
                # 获取数组的数量和长度
                num_clusters, array_length = individual.shape
                # 生成一个与 individual 形状相同的随机数数组
                random_values = np.random.uniform(-180, 180, (num_clusters, array_length))
                # 角度转bit
                random_values_bit, random_values_deg = phase_2_bit(random_values, self.__bit_num)
                # 决定哪些元素需要变异
                mask = np.random.rand(num_clusters, array_length) < self.mutation_rate
                # 应用变异
                individual[mask] = random_values_bit[mask]
        return offspring

    def run(self, phaseBit_mix_init, phaseBit_history_list, fitness_l4_map, phaseBit_target):
        logger.info("population_size=%d, num_generations=%d, num_parents=%d, mutation_rate=%d"
                    % (self.population_size, self.num_generations, self.num_parents, self.mutation_rate))
        # """初始化fitness需要历史数据"""
        self.phaseBitHistoryList = phaseBit_history_list
        self.fitness_l4_map = fitness_l4_map
        # """初始化返回值"""
        self.best_fitness = self.fitness(phaseBit_mix_init)
        self.best_individual = phaseBit_mix_init
        self.best_fitness_history = []
        self.best_individual_history = []
        # """运行遗传算法 -- 初始化阶段"""
        self.initialize_population(phaseBit_mix_init)
        self.init_main_lope_pos(phaseBit_target)
        # """运行遗传算法 -- 搜索阶段"""
        for generation in range(self.num_generations):
            # 选择操作
            selected_parents, selected_fitness_scores = self.selection()
            # 交换操作
            offspring = self.crossover(selected_parents, self.population_size - self.num_parents)
            # 变异操作
            offspring = self.mutation(offspring)
            # 计算后代的适应度值
            offspring_fitness_scores = [self.fitness(individual) for individual in offspring]
            # 更新种群
            self.population = selected_parents + offspring
            # 合并父代和后代的适应度值
            all_fitness_scores = selected_fitness_scores + offspring_fitness_scores
            #
            # 找到当前代的最佳个体
            this_best_index = np.argmin(all_fitness_scores)  # 找到最佳适应度值的索引
            if this_best_index < len(selected_parents):
                this_best_individual = selected_parents[this_best_index]  # 最佳个体来自父代
            else:
                this_best_individual = offspring[this_best_index - len(selected_parents)]  # 最佳个体来自后代
            this_best_fitness = all_fitness_scores[this_best_index]  # 最佳适应度值
            #
            # 更新最佳适应度
            if this_best_fitness < self.best_fitness:
                self.best_fitness = this_best_fitness
                self.best_individual = this_best_individual
            # 记录最佳适应度曲线
            self.best_fitness_history.append(self.best_fitness)
            self.best_individual_history.append(self.best_individual)
            #
            logger.info("generation=%d: self.best_fitness=%f" % (generation, self.best_fitness))
            logger.info("---------------------------------------------------------------------------")
        return self.best_individual, self.best_fitness, self.best_fitness_history, self.best_individual_history




# ============================================= 主方法 ===========================================
# 多波束合成: PS-complex
def multi_beam_ps_complex(phaseRads_list, bit_num):
    # 整理数据, 将所有[0]放第一个, [1]放第二个, [2]放第三个, ……
    phase_mix_prepare_list = [list(item) for item in zip(*phaseRads_list)]
    # PS-complex
    phase_mix_list = []
    phaseBit_mix_list = []
    phaseBitDeg_mix_list = []
    for phase_mix_prepare in phase_mix_prepare_list:
        phase_mix, phaseBit_mix, phaseBitDeg_mix = psm_complex_beam_n(phase_mix_prepare, bit_num)
        phase_mix_list.append(phase_mix)
        phaseBit_mix_list.append(phaseBit_mix)
        phaseBitDeg_mix_list.append(phaseBitDeg_mix)
    return phase_mix_list, phaseBit_mix_list, phaseBitDeg_mix_list


# 多波束合成: QE
def multi_beam_qe(phaseBits_list):
    # 整理数据, 将所有[0]放第一个, [1]放第二个, [2]放第三个, ……
    phaseBit_mix_prepare_list = [list(item) for item in zip(*phaseBits_list)]
    # QE
    phaseBit_mix_list = []
    for phaseBit_mix_prepare in phaseBit_mix_prepare_list:
        phaseBit_mix, random_indices = qe_beam_N(phaseBit_mix_prepare)
        phaseBit_mix_list.append(phaseBit_mix)
    return phaseBit_mix_list


# 计算fitness组
def get_fitness(bit_num, ga, phaseBit):
    # 前置计算, 计算pattern和peaks
    pattern, x, y = phaseBit_2_pattern(phaseBit, bit_num)
    peaks = pattern_2_peaks(pattern)
    #
    # 计算 L0
    l0 = ga.fitness_l0(peaks, pattern)
    # 计算 L1
    l1 = ga.fitness_l1(peaks)
    # 计算 L2
    l2 = ga.fitness_l2(phaseBit)
    # 计算 L3
    l3 = ga.fitness_l3(phaseBit)
    # 计算 L4
    l4 = ga.fitness_l4(phaseBit)
    # 计算 L5
    l5 = ga.fitness_l5(phaseBit, 1)
    # 计算 L
    fitness = ga.fitness(phaseBit)
    logger.info("l=%f, l0=%d, l1=%f, l2=%s, l3=%s, l4=%s, l5=%d"
                % (fitness, l0, l1, l2, l3, l4, l5))
    return fitness, l0, l1, l2, l3, l4, l5


# 扫描的主程序
def main_beam_trace(path_pre, traces, phaseBit_list, bit_num, beam_num, bit_map):
    # 参数设置
    phaseBit_ga_list = []                       # 优化后码阵 phaseBit_list
    path_pre_origin = path_pre + "origin/"      # 图片保存路径: 优化前
    path_pre_ga = path_pre + "ga/"              # 图片保存路径: 优化后
    path_pre_compare = path_pre + "compare/"    # 图片保存路径: 比较
    #
    # ga = GeneticAlgorithmBeamTrace(bit_num, beam_num)
    ga = GeneticAlgorithmBeamTrace(bit_num, beam_num, 30, 30, 6, 0.1)
    rows, cols = phaseBit_list[0].shape
    # main-loop
    for i in range(len(traces)):
        phaseBit = phaseBit_list[i]
        logger.info("[GA Optimization main loop] i=%d(%d)" % (i, len(phaseBit_list)))
        # GA 寻优
        phaseBit_ga, best_fitness, phaseBit_ga_fitness_history, best_individual_history \
            = ga.run(phaseBit, phaseBit_ga_list, bit_map, phaseBit)
        phaseBit_ga_list.append(phaseBit_ga)
        # 计算方向图
        pattern_xyz, x, y = phaseBit_2_pattern(phaseBit, bit_num)
        pattern_xyz_ga, x_ga, y_ga = phaseBit_2_pattern(phaseBit_ga, bit_num)
        # # debug 画图
        # draw_img(phaseBit)
        # draw_img(phaseBit_ga)
        # draw_img(np.abs(pattern_xyz))
        # draw_img(np.abs(pattern_xyz_ga))
        #
        # 保存相位结果
        save_csv(phaseBit, path_pre_origin + "phaseBit_" + str(i) + ".csv")
        save_csv(phaseBit_ga, path_pre_ga + "phaseBit_ga_" + str(i) + ".csv")
        # 设置前一时刻码阵, 开始时刻相等
        if i == 0:
            phaseBit_before = phaseBit
            phaseBit_ga_before = phaseBit_ga
        else:
            phaseBit_before = phaseBit_list[i - 1]
            phaseBit_ga_before = phaseBit_ga_list[i - 1]
        # 统计天线指标
        pg_list, psll, psll_coor, peaks = get_antenna_indicators_normalized_item(beam_num, pattern_xyz)
        pg_list_ga, psll_ga, psll_coor_ga, peaks_ga = get_antenna_indicators_normalized_item(beam_num, pattern_xyz_ga)
        # 统计与前一个码阵的差别
        diff_phaseBit = compare_arrays(phaseBit_before, phaseBit)
        diff_phaseBit_ga = compare_arrays(phaseBit_ga_before, phaseBit_ga)
        # 统计与前一个码阵的相差数量
        phaseBit_diff_count = np.sum(phaseBit != phaseBit_before)
        phaseBit_diff_count_percent = round((phaseBit_diff_count / (rows * cols)) * 100, 4)
        phaseBit_ga_diff_count = np.sum(phaseBit_ga != phaseBit_ga_before)
        phaseBit_ga_diff_count_percent = round((phaseBit_ga_diff_count / (rows * cols)) * 100, 4)
        # 计算 fitness
        fitness, l0, l1, l2, l3, l4, l5 = get_fitness(bit_num, ga, phaseBit)
        fitness_ga, l0_ga, l1_ga, l2_ga, l3_ga, l4_ga, l5_ga = get_fitness(bit_num, ga, phaseBit_ga)
        # 保存图片
        img_text = "(theta,phi)=" + str(traces[i][0]) \
                   + ", count-diff=" + str(phaseBit_diff_count) \
                   + "(" + str(phaseBit_diff_count_percent) + ")" \
                   + ", count-diff(GA)=" + str(phaseBit_ga_diff_count) \
                   + "(" + str(phaseBit_ga_diff_count_percent) + ")" \
                   + ", PSLL=" + str(psll) + ", PSLL(GA)=" + str(psll_ga)
                   # + ", PG=" + str(pg_list) + ", PG(GA)=" + str(pg_list_ga) \
        save_images_3x2(path_pre_compare + "phaseBit_pattern" + str(i) + ".jpg",
                        phaseBit, f"phaseBit", np.abs(pattern_xyz), f"pattern", diff_phaseBit, f"diff(phaseBit)",
                        phaseBit_ga, f"phaseBit(GA)", np.abs(pattern_xyz_ga), f"pattern(GA)", diff_phaseBit_ga,
                        f"diff(phaseBit(GA))",
                        img_text)
        # 保存遗传算法优化结果
        best_fitness_history = phaseBit_ga_fitness_history
        save_line_chart(path_pre_ga + "best_fitness_history" + str(i) + ".jpg", best_fitness_history,
                        "best_fitness_(theta,phi)=" + str(traces[i]), "iteration", "best_fitness", "fitness")
        save_csv([[item] for item in best_fitness_history], path_pre_ga + "best_fitness_history" + str(i) + ".csv")
        # 保存指标
        result_csv = {
            "(theta,phi)": traces[i],
            "pg_list": pg_list,
            "pg_list_GA": pg_list_ga,
            "psll": psll,
            "psll_GA": psll_ga,
            "psll_coor": psll_coor,
            "psll_coor_GA": psll_coor_ga,
            "phase_count_diff": phaseBit_diff_count,
            "phase_count_diff_GA": phaseBit_ga_diff_count,
            "phase_count_percent_diff": phaseBit_diff_count_percent,
            "phase_count_percent_diff_GA": phaseBit_ga_diff_count_percent,
            "fitness": fitness,
            "fitness_ga": fitness_ga,
            "l0": l0,
            "l0_ga": l0_ga,
            "l1": l1,
            "l1_ga": l1_ga,
            "l2": l2,
            "l2_ga": l2_ga,
            "l3": l3,
            "l3_ga": l3_ga,
            "l4": l4,
            "l4_ga": l4_ga,
            "l5": l5,
            "l5_ga": l5_ga,
        }
        save_to_csv([result_csv], path_pre_compare + "result.csv")


# 主程序: 单波束
def main_beam_1_trace_ga(path_pre, bit_num):
    # 生成轨迹指向
    traces = create_scan_traces_theta(0, 90, 0)     # theta方向, (theta, phi): (0, 0) --> (90, 0)
    print("traces:", traces)
    # 生成码阵
    phaseBit_list = traces_2_phaseBits(traces, bit_num)
    # 相邻码阵 GA 优化
    main_beam_trace(path_pre, traces, phaseBit_list, bit_num, len(phaseBit_list[0]))


# 主程序: 多波束
def main_beam_multi_trace_ga(path_pre, bit_num, bit_map):
    logger.info("main_beam_multi_trace_ga: bit_num=%d" % (bit_num))
    # 生成轨迹指向
    traces1 = create_scan_traces_theta(15, 20, 0)   # theta方向, (theta, phi): (5,  0) --> (60,  0)
    traces2 = create_scan_traces_theta(15, 20, 90)  # theta方向, (theta, phi): (5, 90) --> (60, 90)
    logger.info("traces1:%s" % (traces1))
    logger.info("traces2:%s" % (traces2))
    # 生成码阵
    phaseRads1 = traces_2_phaseRads(traces1)
    phaseRads2 = traces_2_phaseRads(traces2)
    # 合成多波束: PS-complex
    # phase_mix_list, phaseBit_mix_list, phaseBitDeg_mix_list = multi_beam_ps_complex([phaseRads1, phaseRads2], bit_num)
    # 合成多波束: QE
    phaseBit1 = phases_rad_2_bit(phaseRads1, bit_num)
    phaseBit2 = phases_rad_2_bit(phaseRads2, bit_num)
    phaseBit_mix_list = multi_beam_qe([phaseBit1, phaseBit2])
    # 相邻码阵 GA 优化
    traces_list = [traces1, traces2]
    traces_mix_list = [list(item) for item in zip(*traces_list)]
    main_beam_trace(path_pre, traces_mix_list, phaseBit_mix_list, bit_num, len(phaseBit_mix_list[0]), bit_map)


# 主程序: 多波束 -- 波束太多时使用
def main_beam_multi_trace_ga_beams(path_pre, bit_num, bit_map):
    logger.info("main_beam_multi_trace_ga_beams: bit_num=%d" % (bit_num))
    traces_list = []
    phaseRads_list = []
    phaseBit_list = []
    # 生成轨迹指向 & 码阵
    phis = np.arange(0, 360, 22.5)      # 16波束
    # phis = np.arange(0, 360, 11.25)      # 32波束
    logger.info("phis:%s" % phis)
    for phi in phis:
        print(phi)
        # 生成轨迹指向
        traces = create_scan_traces_theta(30, 35, phi)   # theta方向, (theta, phi): (30,  phi) --> (35,  phi)
        # 生成码阵
        phaseRads = traces_2_phaseRads(traces)
        # 码阵bit化
        phaseBit = phases_rad_2_bit(phaseRads, bit_num)
        logger.info("traces:%s" % (traces))
        traces_list.append(traces)
        phaseRads_list.append(phaseRads)
        phaseBit_list.append(phaseBit)
    # 合成多波束: PS-complex
    phase_mix_list, phaseBit_mix_list, phaseBitDeg_mix_list = multi_beam_ps_complex(phaseRads_list, bit_num)
    # 合成多波束: QE
    # phaseBit_mix_list = multi_beam_qe(phaseBit_list)
    # 相邻码阵 GA 优化
    traces_mix_list = [list(item) for item in zip(*traces_list)]
    main_beam_trace(path_pre, traces_mix_list, phaseBit_mix_list, bit_num, len(phaseBit_mix_list[0]), bit_map)



# ============================================= 测试方法 ===========================================
def test_fitness_l2():
    ga = GeneticAlgorithmBeamTrace(1, 1)
    phaseBit_history_list = []
    phaseBit_history_list.append(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
    ga.phaseBitHistoryList = phaseBit_history_list
    count, percentage = ga.fitness_l2(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]))
    print("test_fitness_l2: count=%s, percentage=%f" % (count, percentage))
    count, percentage = ga.fitness_l2(np.array([[0, 0, 1], [0, 1, 1], [1, 0, 1]]))
    print("test_fitness_l2: count=%s, percentage=%f" % (count, percentage))
    #
    phaseBit_history_list = []
    phaseBit_history_list.append(np.array([[1, 0, 0], [1, 1, 0], [1, 1, 1]]))
    ga.phaseBitHistoryList = phaseBit_history_list
    count, percentage = ga.fitness_l2(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]))
    print("test_fitness_l2: count=%s, percentage=%f" % (count, percentage))
    count, percentage = ga.fitness_l2(np.array([[0, 0, 1], [0, 1, 1], [1, 0, 1]]))
    print("test_fitness_l2: count=%s, percentage=%f" % (count, percentage))


def test_fitness_l3():
    ga = GeneticAlgorithmBeamTrace(1, 1)
    ga.phaseBitTarget = 1
    phaseBit_history_list = []
    phaseBit_history_list.append(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
    phaseBit_history_list.append(np.array([[1, 0, 0], [1, 1, 0], [0, 0, 1]]))
    phaseBit_history_list.append(np.array([[1, 0, 0], [1, 1, 0], [1, 1, 1]]))
    ga.phaseBitHistoryList = phaseBit_history_list
    count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max \
        = ga.fitness_l3(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]))
    print("test_fitness_l3: count_target=%s, mean_value=%s, deviation_sum=%s, standard_deviation=%f, normalized_std_max=%f"
          % (count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max))
    count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max \
        = ga.fitness_l3(np.array([[0, 0, 1], [0, 1, 1], [1, 0, 1]]))
    print("test_fitness_l3: count_target=%s, mean_value=%s, deviation_sum=%s, standard_deviation=%f, normalized_std_max=%f"
        % (count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max))
    #
    phaseBit_history_list = []
    phaseBit_history_list.append(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
    phaseBit_history_list.append(np.array([[1, 0, 0], [1, 1, 0], [1, 1, 1]]))
    phaseBit_history_list.append(np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]))
    ga.phaseBitHistoryList = phaseBit_history_list
    count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max \
        = ga.fitness_l3(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]))
    print("test_fitness_l3: count_target=%s, mean_value=%s, deviation_sum=%s, standard_deviation=%f, normalized_std_max=%f"
        % (count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max))
    count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max \
        = ga.fitness_l3(np.array([[0, 0, 1], [0, 1, 1], [1, 0, 1]]))
    print("test_fitness_l3: count_target=%s, mean_value=%s, deviation_sum=%s, standard_deviation=%f, normalized_std_max=%f"
        % (count_target, mean_value, deviation_sum, standard_deviation, normalized_std_max))


def test_fitness_l4():
    ga = GeneticAlgorithmBeamTrace(1, 1)
    ga.phaseBitTarget = 1
    ga.fitness_l4_map = {0: 4, 1: 5}
    counts, variance = ga.fitness_l4(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]))
    print("test_fitness_l4: counts=%s, variance=%d" % (counts, variance))
    counts, variance = ga.fitness_l4(np.array([[0, 0, 0], [1, 1, 0], [0, 0, 1]]))
    print("test_fitness_l4: counts=%s, variance=%d" % (counts, variance))
    counts, variance = ga.fitness_l4(np.array([[0, 1, 0], [0, 1, 1], [0, 0, 1]]))
    print("test_fitness_l4: counts=%s, variance=%d" % (counts, variance))


def test_fitness_l0():
    # 多个波束计算码阵
    bit_num = 1
    # point_list = [(30, 0), (30, 90)]
    # point_list = [(30, 0), (40, 90)]
    point_list = [(30, 0), (30, 22.5), (30, 45), (30, 67.5), (30, 90), (30, 112.5), (30, 135), (30, 157.5), (30, 180),
                  (30, 202.5), (30, 225), (30, 247.5), (30, 270), (30, 292.5), (30, 315), (30, 337.5)]
    phaseRads = []
    phaseBits = []
    for point in point_list:
        theta = point[0]
        phi = point[1]
        # 指向生成码阵
        phaseRad = point_2_phase(theta, phi)
        phaseRad = np.rad2deg(phaseRad)
        # 码阵bit化
        phaseBit, phaseDeg = phase_2_bit(phaseRad, bit_num)
        phaseRads.append(phaseRad)
        phaseBits.append(phaseBit)
    # 多波束合成
    phase_mix, phaseBit_mix, phaseBitDeg_mix = psm_complex_beam_n(phaseRads, bit_num)   # PS-complex
    # phaseBit_mix, random_indices = qe_beam_N(phaseBits)                                 # QE
    # 码阵算方向图
    pattern, x, y = phaseBit_2_pattern(phaseBit_mix, bit_num)
    # debug 画图确认多波束合成
    # draw_img(phaseBit_mix)
    # draw_img(np.abs(pattern))
    # 测试GA的fitness_l0
    beam_num = len(point_list)
    ga = GeneticAlgorithmBeamTrace(1, beam_num)
    # 初始化主瓣位置记录
    ga.init_main_lope_pos(phaseBit_mix)
    # case 1
    # 前置计算, 计算pattern和peaks
    pattern, x, y = phaseBit_2_pattern(phaseBit_mix, bit_num)
    peaks = pattern_2_peaks(pattern)
    # 计算 L0
    l0_main_lope_pos_miss = ga.fitness_l0(peaks, pattern)
    print("l0_main_lope_pos_miss:", l0_main_lope_pos_miss)
    # case 2
    # point_list = [(30, 0), (30, 180)]
    point_list = [(30, 0), (30, 22.5), (30, 45), (30, 67.5), (30, 90), (30, 110), (30, 135), (30, 157.5), (30, 180),
                  (30, 202.5), (30, 225), (30, 247.5), (30, 270), (30, 290), (30, 315), (30, 337.5)]
    phaseRads = []
    phaseBits = []
    for point in point_list:
        theta = point[0]
        phi = point[1]
        # 指向生成码阵
        phaseRad = point_2_phase(theta, phi)
        phaseRad = np.rad2deg(phaseRad)
        # 码阵bit化
        phaseBit, phaseDeg = phase_2_bit(phaseRad, bit_num)
        phaseRads.append(phaseRad)
        phaseBits.append(phaseBit)
    # 多波束合成
    phase_mix, phaseBit_mix, phaseBitDeg_mix = psm_complex_beam_n(phaseRads, bit_num)  # PS-complex
    # phaseBit_mix, random_indices = qe_beam_N(phaseBits)                                 # QE
    # 前置计算, 计算pattern和peaks
    pattern, x, y = phaseBit_2_pattern(phaseBit_mix, bit_num)
    peaks = pattern_2_peaks(pattern)
    # 计算 L0
    l0_main_lope_pos_miss = ga.fitness_l0(peaks, pattern)
    print("l0_main_lope_pos_miss:", l0_main_lope_pos_miss)


def test_fitness_l5():
    ga = GeneticAlgorithmBeamTrace(1, 1)
    l5_counts = ga.fitness_l5(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]), 1)
    print("l5_counts:", l5_counts)
    l5_counts = ga.fitness_l5(np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1]]), 0)
    print("l5_counts:", l5_counts)
    l5_counts = ga.fitness_l5(np.array([[0, 0, 1], [0, 1, 0], [0, 0, 1]]), 1)
    print("l5_counts:", l5_counts)
    l5_counts = ga.fitness_l5(np.array([[0, 0, 1], [0, 1, 0], [0, 0, 1]]), 0)
    print("l5_counts:", l5_counts)
    l5_counts = ga.fitness_l5(np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]]), 1)
    print("l5_counts:", l5_counts)
    l5_counts = ga.fitness_l5(np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]]), 0)
    print("l5_counts:", l5_counts)





if __name__ == '__main__':
    logger.info("multi-beam-trace-GA: random method")
    # 主函数
    bit_map = {0: 2048, 1: 2048}
    # main_beam_1_trace_ga("../files/multi-beam-trace/beam1/GA/theta(0,1,90)-phi(0,0,0)/", 1, bit_map)
    main_beam_multi_trace_ga_beams("../files/multi-beam-trace/beam2/QE/L=L1+L4/2025-03-20-1317-16beam-ps-complex/", 1, bit_map)
    # 测试函数
    # test_fitness_l2()
    # test_fitness_l3()
    # test_fitness_l4()
    # test_fitness_l0()
    # test_fitness_l5()